(define (ugen:switch action)
  (define (make-res-filename file-names)
    (if (null? file-names) "RES" (merge-file-names file-names)))
  (define (merge-file-names names)
    (foldr1 (lambda (name1 name2) (string-append name1 "-" name2))
            (map uio:cut-off-ext names)))
  (define (request-data-file-names)
    (norm-ext* "dat" (request-tokens "Static data file names [.dat]: ")))
  (define (norm-ext* ext names)
    (map (lambda (name) (uio:norm-file-name "" ext name)) names))
  (define (request-tokens msg)
    (define input-string #f)
    (define len #f)
    (define pos #f)
    (define tokens #f)
    (define current-token #f)
    (define (current-char) (string-ref input-string pos))
    (define (scan-tokens!)
      (cond ((= pos len) #f)
            ((eqv? (current-char) #\space) (set! pos (+ 1 pos)) (scan-tokens!))
            (else (set! current-token '()) (scan-1-token!))))
    (define (scan-1-token!)
      (cond ((or (= pos len) (eqv? (current-char) #\space))
             (set! tokens (cons (list->string (reverse current-token)) tokens))
             (set! current-token '())
             (scan-tokens!))
            (else
             (set! current-token (cons (current-char) current-token))
             (set! pos (+ 1 pos))
             (scan-1-token!))))
    (newline)
    (display msg)
    (do () ((not (char-ready?))) (read-char))
    (set! input-string (uio:read-line))
    (set! len (string-length input-string))
    (set! pos 0)
    (set! tokens '())
    (scan-tokens!)
    (reverse tokens))
  (define (run-pe)
    (newline)
    (let* ((ann-file-name
             (uio:request-file-name "Annotated program file name" "" "ann"))
           (data-file-names (request-data-file-names))
           (res (make-res-filename data-file-names))
           (program (uio:file->list ann-file-name))
           (static-inputs (append-map uio:file->list data-file-names)))
      (pe-aux ann-file-name data-file-names res program static-inputs)))
  (define (run-pepepe)
    (newline)
    (let* ((ann-file-name
             (uio:request-file-name "Annotated program file name" "xpe" "ann"))
           (res (uio:request-name "Residual program file name " "GGG"))
           (program (uio:file->list ann-file-name))
           (static-inputs (list program)))
      (pe-aux ann-file-name (list ann-file-name) res program static-inputs)))
  (define (generate-residual-program dst program static-inputs)
    (ux:load "xmainpe")
    (umainpe:generate-residual-program dst program static-inputs)
    (set! umainpe:generate-residual-program #f)
    (set! xapply #f))
  (define (pe-aux src data-file-names res program static-inputs)
    (let ((dst (string-append res ".mwr")) (scm (string-append res ".scm")))
      (check-static-inputs program static-inputs)
      (newline)
      (display "Residual program generation:")
      (newline)
      (display "   pe( ")
      (display src)
      (display " , ")
      (display data-file-names)
      (display " ) -> ")
      (display dst)
      (newline)
      (ux:load "xpe")
      (generate-residual-program dst program static-inputs)
      (newline)
      (display "Residual program has been written into ")
      (display dst)
      (newline)
      (post-processing dst scm)))
  (define (check-static-inputs prog data)
    (let ((s-fundef* (caddr prog)) (svn (car (cdaadr prog))) (rf (car prog)))
      (if (not (= (length svn) (length data)))
        (begin (error "Mismatch in mumber of data files")))))
  (define (run-pepe)
    (newline)
    (let* ((ann (uio:request-file-name "Annotated program file name" "" "ann"))
           (res (uio:request-name "Residual program file name " "GENGEN"))
           (dst (string-append res ".mwr"))
           (scm (string-append res ".scm"))
           (program (uio:file->list (string-append **unmix-path** "xpe.ann")))
           (static-inputs (list (uio:file->list ann))))
      (newline)
      (display "Generation of the Residual Program Generator:")
      (newline)
      (display "   pe( xpe.ann , ")
      (display (list ann))
      (display " ) -> ")
      (display dst)
      (newline)
      (ux:load "xpe")
      (generate-residual-program dst program static-inputs)
      (newline)
      (display "Residual program generator has been written into ")
      (display dst)
      (newline)
      (post-processing dst scm)))
  (define (run-gen)
    (newline)
    (let* ((gen (uio:request-file-name "Generator file name" "" "scm"))
           (data-file-names (request-data-file-names))
           (res (make-res-filename data-file-names))
           (dst (string-append res ".mwr"))
           (scm (string-append res ".scm"))
           (static-inputs (append-map uio:file->list data-file-names)))
      (newline)
      (display "Residual program generation:")
      (newline)
      (display "   ")
      (display gen)
      (display "( ")
      (display (list data-file-names))
      (display " ) -> ")
      (display dst)
      (newline)
      (load gen)
      (generate-residual-program dst '() static-inputs)
      (newline)
      (display "Residual program has been written into ")
      (display dst)
      (newline)
      (post-processing dst scm)))
  (define (run-gengen)
    (newline)
    (let* ((ann (uio:request-file-name "Annotated program file name" "" "ann"))
           (res (uio:request-name "Residual program file name " "GENGEN"))
           (dst (string-append res ".mwr"))
           (scm (string-append res ".scm"))
           (static-inputs (list (uio:file->list ann))))
      (ux:load "xggg")
      (newline)
      (display "Generation of the Residual Program Generator:")
      (newline)
      (display "   gengen( ")
      (display ann)
      (display " ) -> ")
      (display dst)
      (newline)
      (generate-residual-program dst '() static-inputs)
      (newline)
      (display "Residual program generator has been written into ")
      (display dst)
      (newline)
      (post-processing dst scm)))
  (define (post-processing src dst)
    (let ((pgm (uio:cut-off-ext src)) (program #f))
      (newline)
      (display "Post-processing:")
      (newline)
      (display "   post( ")
      (display src)
      (display " ) -> ")
      (display dst)
      (newline)
      (set! program (uio:file->list src))
      (ux:load "xcgr")
      (set! program (ucgr:main pgm pgm program))
      (set! ucgr:main #f)
      (ux:load "xar")
      (set! program (uar:main pgm pgm program))
      (set! uar:main #f)
      (ux:load "xcgr")
      (set! program (ucgr:main pgm pgm program))
      (set! ucgr:main #f)
      (ux:load "xensg")
      (set! program (uensg:main pgm pgm program))
      (set! uensg:main #f)
      (uio:list->pp-file dst program 79)
      (newline)
      (display "Target program has been written into ")
      (display dst)
      (newline)))
  (case action
    ((pe) (run-pe))
    ((pepe) (run-pepe))
    ((pepepe) (run-pepepe))
    ((gengen) (run-gengen))
    ((gen) (run-gen))))

